from math import radians, sin, cos, atan2, sqrt

from fastapi import Depends
from sqlalchemy import func
from sqlalchemy.orm import Session
from app.database import engine
from app.models import Users, LocationHistory
from app.schemas.user import UserInfo, UserHistoryLocationSM


def distance_from(longitude1, latitude1, longitude2, latitude2):
    earth_radius_km = 6371.0
    lat1 = radians(latitude1)
    lon1 = radians(longitude1)
    lat2 = radians(latitude2)
    lon2 = radians(longitude2)
    dlon = lon2 - lon1
    dlat = lat2 - lat1
    a = sin(dlat / 2) ** 2 + cos(lat1) * cos(lat2) * sin(dlon / 2) ** 2
    c = 2 * atan2(sqrt(a), sqrt(1 - a))
    distance_km = earth_radius_km * c
    return distance_km


class UserServices(object):

    @staticmethod
    def get_user_by_id(user_id: int):
        with Session(engine) as session:
            result = session.get(Users, user_id)
            return result

    @staticmethod
    def get_user_by_username(username: str):
        with Session(engine) as session:
            result = session.query(Us ers).filter(Users.name == username).first()
            return result

    @staticmethod
    def edit_user_info(user_id: int, form):
        with Session(engine) as session:
            user = session.query(Users).filter(Users.id == user_id)
            user.update(form.dict())
            session.commit()
            return True

    @staticmethod
    def location_history_store(user_id: int, form: UserHistoryLocationSM):
        with Session(engine) as session:
            form_dict = form.dict()
            form_dict['uid'] = user_id
            obj = LocationHistory(**form_dict)
            session.add(obj)
            session.commit()
            return True

    @staticmethod
    def nearby_users(longitude: float, latitude: float, radius: float = 10, page: int = 1, page_size: int = 100):
        offset = (page - 1) * page_size
        # 计算距离
        distance = func.ST_DISTANCE_SPHERE(
            func.ST_GEOPOINT(Users.latitude, Users.longitude),
            func.ST_GEOPOINT(latitude, longitude)
        )
        with Session(engine) as session:
            # 查询附近的人，按距离升序排列
            total = session.query(func.count()).select_from(Users).filter(distance <= radius * 1000).order_by(
                distance).scalar()
            users = session.query(Users).filter(distance <= radius * 1000).order_by(distance).offset(offset).limit(
                page_size).all()

        new_users = []
        for user in users:
            user.distance_km = distance_from(longitude, latitude, user.longitude, user.latitude)
            for friend in user.friends:
                if friend.uid == user.id:
                    user.is_friends = True
                else:
                    user.is_friends = False
            new_users.append(user)

        return {'list': users, 'total': total}
